/**
 * Generate code from /{{projectName}}-core/src/main/java/{{packageName}}/core/{{modules}}/service/impl/{{entities@SQL}}ServiceImpl.java.hbs
 */
// @SkipOverwrite
package cn.ibizlab.core.ad.service.impl;

import cn.ibizlab.core.ad.domain.SysOrganization;
import cn.ibizlab.core.ad.filter.SysOrganizationSearchContext;
import cn.ibizlab.util.ad.SysOrganizationTreeUtil;
import cn.ibizlab.util.enums.Entities;
import cn.ibizlab.util.errors.BadRequestAlertException;
import cn.ibizlab.util.errors.NotFoundException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import java.io.Serializable;
import java.util.*;

/**
 * 实体[组织机构] 服务对象接口实现
 *
 * @author generator
 */
@Slf4j
@Service("SysOrganizationService")
public class SysOrganizationServiceImpl extends AbstractSysOrganizationService {

    private Object lock = new Object();

    @Override
    @Cacheable(value = "sysorganization", key = "'dc:'+#p0.dc")
    public List<SysOrganization> all(SysOrganization dto) {
        synchronized (lock) {
            SysOrganizationSearchContext context = new SysOrganizationSearchContext();
            context.setSort("sort,asc");
            return this.listDefault(new SysOrganizationSearchContext());
        }
    }

    @Override
    @Cacheable(value = "sysorganization", key = "'tree:'+#p0.dc")
    public List<SysOrganization> treeList(SysOrganization dto) {
        synchronized (lock) {
            List<SysOrganization> all = getSelf().all(dto);
            String rootId = dto.getOrDefault("root", null);
            Map<String, List<SysOrganization>> map = new HashMap<>();
            List<SysOrganization> list = new ArrayList<>();

            for (SysOrganization item : all) {
                list.add(item.copyTo(new SysOrganization(), false));
            }

            for (SysOrganization item : list) {
                String parentId = item.getParentId();
                if (!ObjectUtils.isEmpty(parentId)) {
                    List<SysOrganization> group = map.getOrDefault(parentId, new ArrayList<>());
                    group.add(item);
                    map.put(parentId, group);
                }
            }

            // 遍历所有的Map对象，将其放入对应的parent_id对应的List的children属性中
            for (SysOrganization item : list) {
                List<SysOrganization> children = map.get(item.getId());
                if (!ObjectUtils.isEmpty(children)) {
                    item.setChildren(children);
                }
            }

            // 将没有parent_id的Map对象放入根节点List中，并返回根节点List
            List<SysOrganization> result = new ArrayList<>();
            for (SysOrganization item : list) {
                if ((item.getParentId() == null && rootId == null) || (rootId != null && rootId.equals(item.getParentId()))) {
                    result.add(item);
                    if (item.getParentId() != null)
                        item.setParentIds(Arrays.asList(item.getParentId()));
                    calculateParentAndSubIds(item);
                }
            }
            return result;
        }
    }

    private void calculateParentAndSubIds(SysOrganization node) {
        if(node.getParentIds()==null)
            node.setParentIds(new ArrayList<>());
        if(node.getSubIds()==null)
            node.setSubIds(new ArrayList<>());
        if(!ObjectUtils.isEmpty(node.getChildren())) {
            node.getChildren().forEach(child -> {
                child.setParentIds(new ArrayList<>());
                child.getParentIds().addAll(node.getParentIds());
                child.getParentIds().add(node.getId());
                calculateParentAndSubIds(child);
                node.getSubIds().add(child.getId());
                node.getSubIds().addAll(child.getSubIds());
            });
        }
    }

    @Override
    @Cacheable(value = "sysorganization", key = "'options:'+#p0.id")
    public List<SysOrganization> options(SysOrganization dto) {
        SysOrganization node = findNodeByIdOrCode(dto);
        if(node !=null)
            return Arrays.asList(node.copyTo(new SysOrganization(),false).setParentId(null));
        return getSelf().treeList(dto);
    }

    private SysOrganization findNodeByIdOrCode(SysOrganization dto) {
        List<SysOrganization> treeList = this.getSelf().treeList(dto);
        SysOrganization node = null;
        if(!ObjectUtils.isEmpty(dto.getId())){
            node = findNodeById(treeList,dto.getId());
            if(node ==null)
                node = findNodeByCode(treeList,dto.getId());
        }
        else if(!ObjectUtils.isEmpty(dto.getOrganizationNumber())){
            node = findNodeByCode(treeList,dto.getId());
        }
        return node;
    }

    private SysOrganization findNodeById(List<SysOrganization> treeList, String id) {
        for(SysOrganization item : treeList) {
            if (item.getId().equals(id))
                return item;
            else if (!ObjectUtils.isEmpty(item.getChildren())) {
                SysOrganization ret = findNodeById(item.getChildren(), id);
                if(ret != null)
                    return ret;
            }

        }
        return null;
    }

    private SysOrganization findNodeByCode(List<SysOrganization> treeList, String code) {
        for(SysOrganization item : treeList) {
            if (item.getOrganizationNumber().equals(code))
                return item;
            else if (!ObjectUtils.isEmpty(item.getChildren())) {
                SysOrganization ret = findNodeByCode(item.getChildren(), code);
                if(ret != null)
                    return ret;
            }
        }
        return null;
    }

    @Override
    public String findOrganizationId(SysOrganization dto) {
        SysOrganization sysOrganization = null;
        if(!ObjectUtils.isEmpty(dto.getId())) {
            sysOrganization = super.getById(dto.getId());
            if (sysOrganization != null)
                return sysOrganization.getId();
        }
        LambdaQueryWrapper<SysOrganization> query = Wrappers.lambdaQuery();
        if(!ObjectUtils.isEmpty(dto.getDc()))
            query.eq(SysOrganization::getDc,dto.getDc());
        if(!ObjectUtils.isEmpty(dto.getId()))
            query.eq(SysOrganization::getOrganizationNumber,dto.getId());
        else if(!ObjectUtils.isEmpty(dto.getOrganizationNumber()))
            query.eq(SysOrganization::getOrganizationNumber,dto.getOrganizationNumber());
        else if(!ObjectUtils.isEmpty(dto.getOrganizationName()))
            query.eq(SysOrganization::getOrganizationName,dto.getOrganizationName());
        else
            return null;
        sysOrganization = this.getOne(query,false);
        if (sysOrganization != null)
            return sysOrganization.getId();
        return null;
    }

    @Override
    @Cacheable(value = "sysorganization", key = "'parentids:'+#p0.id")
    public List<String> parentIds(SysOrganization dto) {
        List<String> ids = new ArrayList<>();
        try {
            SysOrganization node = findNodeByIdOrCode(dto);
            if (node != null)
                ids = node.getParentIds();
        }catch (Exception ex) {
            return ids;
        }
        return ids;
    }

    @Override
    @Cacheable(value = "sysorganization", key = "'subids:'+#p0.id")
    public List<String> subIds(SysOrganization dto) {
        List<String> ids = new ArrayList<>();
        try {
            SysOrganization node = findNodeByIdOrCode(dto);
            if (node != null)
                ids = node.getSubIds();
        }catch (Exception ex) {
            return ids;
        }
        return ids;
    }

    @Override
    public SysOrganization get(SysOrganization et) {
        SysOrganization rt = this.baseMapper.selectEntity(et);
        if(rt == null) {
            LambdaQueryWrapper<SysOrganization> query = Wrappers.lambdaQuery();
            if(!ObjectUtils.isEmpty(et.getDc()))
                query.eq(SysOrganization::getDc,et.getDc());
            rt = this.getOne(query.eq(SysOrganization::getOrganizationNumber, et.getId()), false);
        }
        if(rt == null)
            throw new NotFoundException("数据不能存在", Entities.SYS_ORGANIZATION.toString(),et.getId());
        rt.copyTo(et,true);
        //设置 [部门]
        getDepartments(et);
        return et;
    }

    @Override
    public SysOrganization getById(Serializable id) {
        SysOrganization sysOrganization = super.getById(id);
        if(sysOrganization == null)
            sysOrganization = this.getOne(Wrappers.<SysOrganization>lambdaQuery().eq(SysOrganization::getOrganizationNumber,id),false);
        return sysOrganization;
    }

    @Override
    public List<SysOrganization> items(SysOrganization dto) {
        SysOrganizationSearchContext context = new SysOrganizationSearchContext();
        String orgId = dto.getId();
        if(!ObjectUtils.isEmpty(orgId)) {
            orgId = this.findOrganizationId(dto);
            if(!ObjectUtils.isEmpty(orgId)) {
                context.setParentIdEQ(orgId);
                List<SysOrganization> list = this.listDefault(context);
                SysOrganization root = this.getById(orgId);
                if (root != null) {
                    root.setParentId(null);
                    list.add(0, root);
                }
                return list;
            }
        }
        List<SysOrganization> list = this.listMyOrg(context);
        list.forEach(item->item.setParentId(null));
        return list;
    }

    @Autowired
    SysOrganizationTreeUtil organizationTreeUtil;

    /**
     * 更新时校验上级单位是否为当前单位或当前单位的子单位
     * @param et
     * @return
     */
    @Override
    @CacheEvict(value = "sysorganization", allEntries = true)
    public boolean update(SysOrganization et) {
        String orgId = et.getId();
        String parentOrgId = et.getParentId();
        if(!ObjectUtils.isEmpty(parentOrgId) && !ObjectUtils.isEmpty(orgId)){
            if(parentOrgId.equals(orgId)){
                throw new BadRequestAlertException("不支持将当前组织设置为上级组织", Entities.SYS_ORGANIZATION.toString(),orgId);
            }
            List<String> subOrgIds = organizationTreeUtil.getSubOrgIdsByOrgId(orgId);
            if(!ObjectUtils.isEmpty(subOrgIds) && subOrgIds.contains(parentOrgId)) {
                throw new BadRequestAlertException("不支持将当前组织的子组织设置为上级组织", Entities.SYS_ORGANIZATION.toString(),orgId);
            }
        }
        return super.update(et);
    }

    /**
     * 查询当前组织的上级组织
     * @param context
     * @return
     */
    @Override
    public Page<SysOrganization> searchParentOrg(SysOrganizationSearchContext context) {

        if(ObjectUtils.isEmpty(context.getContextParentKey()))
            return new PageImpl<>(new ArrayList<>(), context.getPageable(), 0);

        //当前组织id
        String orgId = context.getContextParentKey().toString();
        //排除当前组织及下级组织
        List<String> excludeOrg = Arrays.asList(orgId);
        List<String> subOrgIds = organizationTreeUtil.getSubOrgIdsByOrgId(orgId);
        if(!ObjectUtils.isEmpty(subOrgIds))
           excludeOrg.addAll(subOrgIds);

        context.setIdNOTIN(String.join(",",excludeOrg));
        return super.searchParentOrg(context);

    }

    @Override
    @CacheEvict(value = "sysorganization", allEntries = true)
    public boolean create(SysOrganization et) {
        return super.create(et);
    }

    @Override
    @CacheEvict(value = "sysorganization", allEntries = true)
    public boolean remove(SysOrganization et) {
        return super.remove(et);
    }

    @Override
    @CacheEvict(value = "sysorganization", allEntries = true)
    public SysOrganization cacheEvict(SysOrganization dto) {
        return super.cacheEvict(dto);
    }
}